import os
import sys
from tkinter import filedialog, messagebox, Tk, Button, Label, Frame, StringVar
from comtypes.client import CreateObject
import pythoncom
import threading
from datetime import datetime
import subprocess
import time
import shutil  # 添加shutil模块用于文件复制


class PDFConverter:
    def __init__(self):
        """
        初始化PDF转换器类
        设置基本变量并创建用户界面
        """
        # 初始化主要变量
        self.file_paths = []  # 存储选中的文件路径
        self.pdf_files = []  # 存储找到的PDF文件路径
        self.output_dir = ""  # 存储输出目录路径
        self.is_converting = False  # 转换状态标志
        self.wps_app = None  # WPS应用程序实例

        # 创建主窗口并设置基本属性
        self.root = Tk()
        self.root.title("Word转PDF工具 (自动分类)")
        self.root.geometry("460x560")  # 设置窗口大小
        self.root.resizable(True, True)  # 允许调整窗口大小

        # 创建状态显示变量
        self.status_var = StringVar()
        self.status_var.set("准备就绪")

        # 设置界面
        self.setup_ui()

        # 绑定关闭窗口事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def setup_ui(self):
        """
        创建和配置用户界面
        设置布局、按钮和标签
        """
        # 创建标题区域
        title_frame = Frame(self.root, pady=20)
        title_frame.pack()
        Label(
            title_frame,
            text="Word批量转PDF (WPS)",
            font=("Microsoft YaHei UI", 16, "bold")
        ).pack()

        # 创建说明标签
        instruction_frame = Frame(self.root)
        instruction_frame.pack(pady=10)
        Label(
            instruction_frame,
            text="使用说明：\n1. 选择要转换的Word文件\n2. 选择PDF输出位置\n3. 点击开始转换",
            font=("Microsoft YaHei UI", 10),
            justify="left"
        ).pack()

        # 创建主要按钮
        button_frame = Frame(self.root)
        button_frame.pack(pady=20)

        # 定义按钮样式
        button_style = {
            "width": 25,
            "height": 2,
            "font": ("Microsoft YaHei UI", 10),
            "bg": "#f0f0f0",
            "relief": "raised"
        }

        # 创建三个主要功能按钮
        Button(
            button_frame,
            text="选择Word文件(支持多选)",
            command=self.load_files,
            **button_style
        ).pack(pady=10)

        Button(
            button_frame,
            text="选择输出目录",
            command=self.set_output_folder,
            **button_style
        ).pack(pady=10)

        Button(
            button_frame,
            text="开始转换",
            command=self.start_conversion,
            **button_style
        ).pack(pady=10)

        # 创建状态显示区域
        status_frame = Frame(self.root)
        status_frame.pack(pady=20, fill="x", padx=20)
        Label(
            status_frame,
            textvariable=self.status_var,
            font=("Microsoft YaHei UI", 9),
            wraplength=350  # 设置文本自动换行
        ).pack()

        # 创建页脚信息
        footer_frame = Frame(self.root)
        footer_frame.pack(side="bottom", pady=10)
        Label(
            footer_frame,
            text="© 2024 PDF转换工具 V1.0 (WPS版)",
            font=("Microsoft YaHei UI", 8)
        ).pack()

    def load_files(self):
        """
        加载Word文件，支持选择文件夹
        """
        if self.is_converting:
            messagebox.showwarning("警告", "正在转换中，请等待当前任务完成...")
            return

        # 添加选择方式的对话框
        choice = messagebox.askyesno(
            "选择方式",
            "是否选择整个文件夹？\n'是'：选择文件夹及其子文件夹中的所有Word文件\n'否'：手动选择单个或多个文件"
        )

        if choice:
            # 选择文件夹
            folder = filedialog.askdirectory(title="选择包含Word文件的文件夹")
            if folder:
                self.file_paths = []
                self.pdf_files = []  # 重置PDF文件列表
                # 遍历文件夹及其子文件夹
                for root, _, files in os.walk(folder):
                    for file in files:
                        file_path = os.path.join(root, file)
                        normalized_path = os.path.abspath(file_path).replace('/', '\\')
                        if os.path.exists(normalized_path):
                            if file.endswith(('.doc', '.docx')):
                                self.file_paths.append(normalized_path)
                            elif file.endswith('.pdf'):  # 检测PDF文件
                                self.pdf_files.append(normalized_path)

                word_count = len(self.file_paths)
                pdf_count = len(self.pdf_files)

                message = ""
                if word_count > 0:
                    message += f"已找到 {word_count} 个Word文件\n"
                if pdf_count > 0:
                    message += f"已找到 {pdf_count} 个PDF文件"

                if word_count > 0 or pdf_count > 0:
                    self.status_var.set(message)
                    messagebox.showinfo("成功", message)
                else:
                    self.status_var.set("所选文件夹中未找到Word或PDF文件")
                    messagebox.showwarning("警告", "所选文件夹中未找到Word或PDF文件")
        else:
            # 原有的文件选择逻辑
            files = filedialog.askopenfilenames(
                title="选择需要转换的Word文件",
                filetypes=[
                    ("Word文件", "*.docx;*.doc"),
                    ("所有文件", "*.*")
                ]
            )

            if files:
                # 处理和验证选中的文件
                self.file_paths = []
                self.pdf_files = []  # 重置PDF文件列表
                invalid_files = []

                for file_path in files:
                    # 规范化文件路径
                    normalized_path = os.path.abspath(file_path).replace('/', '\\')

                    # 验证文件是否存在且可访问
                    if os.path.exists(normalized_path):
                        if normalized_path.lower().endswith(('.doc', '.docx')):
                            self.file_paths.append(normalized_path)
                        elif normalized_path.lower().endswith('.pdf'):
                            self.pdf_files.append(normalized_path)
                    else:
                        invalid_files.append(file_path)

                # 更新状态并通知用户
                word_count = len(self.file_paths)
                pdf_count = len(self.pdf_files)

                message = ""
                if word_count > 0:
                    message += f"已选择 {word_count} 个Word文件\n"
                if pdf_count > 0:
                    message += f"已选择 {pdf_count} 个PDF文件"

                if word_count > 0 or pdf_count > 0:
                    self.status_var.set(message)
                    messagebox.showinfo("成功", message)

                if invalid_files:
                    messagebox.showwarning(
                        "警告",
                        f"以下 {len(invalid_files)} 个文件无法访问：\n" +
                        "\n".join(os.path.basename(f) for f in invalid_files)
                    )
            else:
                self.status_var.set("未选择任何文件")

    def set_output_folder(self):
        """
        设置PDF文件的输出目录
        """
        if self.is_converting:
            messagebox.showwarning("警告", "正在转换中，请等待当前任务完成...")
            return

        # 选择输出目录
        folder = filedialog.askdirectory(title="选择PDF文件输出位置")

        if folder:
            # 规范化输出路径
            self.output_dir = os.path.abspath(folder).replace('/', '\\')

            # 尝试创建输出目录
            try:
                os.makedirs(self.output_dir, exist_ok=True)
                self.status_var.set(f"输出目录: {self.output_dir}")
                messagebox.showinfo("成功", "已设置输出目录")
            except Exception as e:
                messagebox.showerror("错误", f"创建输出目录失败：{str(e)}")
                self.output_dir = ""
        else:
            self.status_var.set("未选择输出目录")

    def convert_single_file(self, file_path, wps_app):
        """
        使用WPS转换单个Word文件到PDF，确保完全保持原始文件夹结构
        使用传入的WPS应用程序实例
        """
        try:
            if not os.path.exists(file_path):
                return False, f"文件不存在: {file_path}"

            # 获取源文件所在的根目录（第一个选中文件的父目录）
            root_dir = os.path.dirname(os.path.commonpath(self.file_paths))

            # 计算从根目录到当前文件的相对路径
            rel_dir = os.path.dirname(file_path)[len(root_dir):].lstrip('\\/')

            # 检查输出目录是否与源文件目录相同或包含关系
            file_dir = os.path.dirname(file_path)
            if self.output_dir == file_dir or self.output_dir.startswith(file_dir) or file_dir.startswith(self.output_dir):
                # 如果输出目录与源文件目录相同或有包含关系，创建一个新的子文件夹
                output_folder = os.path.join(self.output_dir, "转换后的PDF文件", rel_dir)
            else:
                # 否则使用原来的输出路径
                output_folder = os.path.join(self.output_dir, rel_dir)
                
            os.makedirs(output_folder, exist_ok=True)

            try:
                # 打开文档
                doc = wps_app.Documents.Open(file_path)

                # 创建PDF文件，保持相同的文件名
                output_name = os.path.splitext(os.path.basename(file_path))[0] + ".pdf"
                output_path = os.path.join(output_folder, output_name)
                output_path = os.path.abspath(output_path).replace('/', '\\')

                # WPS保存为PDF的方法
                # 注意：WPS的SaveAs方法参数可能与MS Office不同
                # 使用ExportAsFixedFormat方法 (如果WPS支持)
                try:
                    # 尝试使用ExportAsFixedFormat方法 (类似MS Office)
                    doc.ExportAsFixedFormat(output_path, 17)  # 17表示PDF格式
                except:
                    try:
                        # 备选方法：使用SaveAs方法
                        doc.SaveAs(output_path, 17)  # 17通常表示PDF格式
                    except:
                        # 如果上述方法都失败，尝试使用另一种WPS特有的方法
                        doc.SaveAs2(output_path, FileFormat=17)

                # 关闭文档
                doc.Close(SaveChanges=False)

                return True, output_path

            except Exception as e:
                return False, f"转换过程出错: {str(e)}"

        except Exception as e:
            return False, f"处理文件出错: {str(e)}"

    def copy_pdf_files(self):
        """
        复制PDF文件到输出目录，保持原始文件夹结构
        """
        if not self.pdf_files or not self.output_dir:
            return 0, []

        success_count = 0
        error_files = []

        # 获取源文件所在的根目录
        if self.file_paths:
            # 如果有Word文件，使用相同的根目录
            root_dir = os.path.dirname(os.path.commonpath(self.file_paths + self.pdf_files))
        else:
            # 如果只有PDF文件
            root_dir = os.path.dirname(os.path.commonpath(self.pdf_files))

        for pdf_path in self.pdf_files:
            try:
                # 检查是否被用户取消
                if not self.is_converting:
                    break

                # 计算从根目录到当前文件的相对路径
                rel_dir = os.path.dirname(pdf_path)[len(root_dir):].lstrip('\\/')

                # 检查输出目录是否与源文件目录相同或包含关系
                pdf_dir = os.path.dirname(pdf_path)
                if self.output_dir == pdf_dir or self.output_dir.startswith(pdf_dir) or pdf_dir.startswith(self.output_dir):
                    # 如果输出目录与源文件目录相同或有包含关系，创建一个新的子文件夹
                    output_folder = os.path.join(self.output_dir, "转换后的PDF文件", rel_dir)
                else:
                    # 否则使用原来的输出路径
                    output_folder = os.path.join(self.output_dir, rel_dir)

                os.makedirs(output_folder, exist_ok=True)

                # 创建目标路径
                output_path = os.path.join(output_folder, os.path.basename(pdf_path))

                # 复制PDF文件
                shutil.copy2(pdf_path, output_path)
                success_count += 1

            except Exception as e:
                error_files.append((pdf_path, f"复制PDF文件失败: {str(e)}"))

        return success_count, error_files

    def batch_convert(self):
        """
        批量转换文件的主要逻辑
        使用单个WPS实例处理所有文件
        """
        if not self.file_paths and not self.pdf_files:
            messagebox.showerror("错误", "请先选择要处理的文件和输出目录！")
            return

        if not self.output_dir:
            messagebox.showerror("错误", "请先选择输出目录！")
            return

        # 创建输出目录
        os.makedirs(self.output_dir, exist_ok=True)

        success_count = 0
        error_files = []
        total_word_files = len(self.file_paths)
        wps_app = None

        # 首先复制PDF文件
        if self.pdf_files:
            self.status_var.set(f"正在复制 {len(self.pdf_files)} 个PDF文件...")
            self.root.update()
            pdf_success, pdf_errors = self.copy_pdf_files()
            success_count += pdf_success
            error_files.extend(pdf_errors)

        # 然后处理Word文件
        if self.file_paths:
            try:
                # 初始化COM组件
                pythoncom.CoInitialize()

                # 创建单个WPS应用实例
                try:
                    # 尝试创建WPS应用实例
                    wps_app = CreateObject('WPS.Application')
                except:
                    # 如果失败，尝试创建金山WPS应用实例 (可能的另一个COM名称)
                    try:
                        wps_app = CreateObject('KWPS.Application')
                    except:
                        # 如果仍然失败，尝试创建ET应用实例 (WPS的另一个可能名称)
                        wps_app = CreateObject('ET.Application')

                wps_app.Visible = False
                wps_app.DisplayAlerts = False

                # 开始转换流程
                for index, file_path in enumerate(self.file_paths, 1):
                    # 检查是否被用户取消
                    if not self.is_converting:
                        break

                    # 更新状态显示
                    self.status_var.set(
                        f"正在转换 {index}/{total_word_files}: {os.path.basename(file_path)}"
                    )
                    self.root.update()

                    # 转换单个文件
                    success, result = self.convert_single_file(file_path, wps_app)

                    if success:
                        success_count += 1
                    else:
                        error_files.append((file_path, result))

            except Exception as e:
                messagebox.showerror("错误", f"转换过程中发生错误: {str(e)}\n\n请确认已安装WPS Office并且可以正常使用。")

            finally:
                # 清理WPS应用实例
                if wps_app:
                    try:
                        wps_app.Quit()
                        del wps_app
                    except:
                        pass

                # 确保COM组件被释放
                pythoncom.CoUninitialize()

                # 强制终止可能残留的WPS进程
                self.cleanup_wps_processes()

        # 生成转换报告
        total_files = total_word_files + len(self.pdf_files)
        self.create_conversion_report(success_count, error_files, total_files)

        # 重置转换状态
        self.is_converting = False
        self.status_var.set("处理完成")

    def cleanup_wps_processes(self):
        """
        清理可能残留的WPS进程
        """
        try:
            # 使用系统命令查找可能由此程序创建的WPS进程
            if sys.platform == "win32":
                # 尝试终止WPS进程
                subprocess.run("taskkill /f /im wps.exe /fi \"WINDOWTITLE eq *转换临时*\"",
                               shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
                # 尝试终止WPS文字进程
                subprocess.run("taskkill /f /im wpsoffice.exe",
                               shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
        except:
            pass

    def on_closing(self):
        """
        窗口关闭时的清理操作
        """
        if self.is_converting:
            if messagebox.askyesno("警告", "转换正在进行中，确定要退出吗？"):
                self.is_converting = False
                time.sleep(0.5)  # 给转换线程一点时间停止
                self.cleanup_wps_processes()
                self.root.destroy()
        else:
            self.cleanup_wps_processes()
            self.root.destroy()

    def create_conversion_report(self, success_count, error_files, total_files):
        """
        创建转换报告并显示结果
        """
        # 显示完成消息
        if success_count > 0:
            messagebox.showinfo(
                "完成",
                f"转换完成！\n成功: {success_count}\n失败: {len(error_files)}"
            )

        # 如果有错误，创建错误日志
        if error_files:
            log_path = os.path.join(self.output_dir, "转换错误日志.txt")
            try:
                with open(log_path, "w", encoding="utf-8") as f:
                    f.write(f"转换时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
                    for file_path, error in error_files:
                        f.write(f"文件: {os.path.basename(file_path)}\n")
                        f.write(f"错误: {error}\n\n")

                messagebox.showwarning(
                    "警告",
                    f"部分文件转换失败，详细信息已保存到：\n{log_path}"
                )
            except Exception as e:
                messagebox.showerror(
                    "错误",
                    f"创建错误日志文件失败：{str(e)}"
                )

    def start_conversion(self):
        """
        开始转换过程
        验证必要条件并启动转换线程
        """
        if self.is_converting:
            messagebox.showwarning("警告", "转换已在进行中...")
            return

        if (not self.file_paths and not self.pdf_files) or not self.output_dir:
            messagebox.showerror("错误", "请先选择要处理的文件和输出目录！")
            return

        # 开始转换
        self.is_converting = True
        threading.Thread(target=self.batch_convert, daemon=True).start()

    def run(self):
        """
        运行应用程序
        """
        self.root.mainloop()


if __name__ == "__main__":
    # 创建应用实例并运行
    app = PDFConverter()
    app.run()
